#include "xlcomm/net/buffer.h"

#include <errno.h>
#include <sys/uio.h>

#include "xlcomm/net/detail/sockets_ops.h"

namespace xlcomm {
namespace net {

const char Buffer::kCrLf[] = "\r\n";

ssize_t Buffer::ReadFromFd(int fd, int* saved_errno) {
  // 使用 scatter/gather I/O 兼顾了内存使用量和效率
  // 1.extrabuf足够大，一次64K缓冲足够容纳千兆网在500us内全速收到的数据
  // 2.level trigger下，只调一次read不会丢失数据，高效且不影响其它连接
  char extrabuf[65536];
  struct iovec vec[2];
  size_t writable = WritableBytes();
  vec[0].iov_base = WriterPtr();
  vec[0].iov_len = writable;
  vec[1].iov_base = extrabuf;
  vec[1].iov_len = sizeof(extrabuf);
  // when there is enough space in this buffer, don't read into extrabuf.
  const int iovcnt = (writable < sizeof extrabuf) ? 2 : 1;
  ssize_t n = sockets::readv(fd, vec, iovcnt);
  if (n < 0) {
    *saved_errno = errno;
  } else if (static_cast<size_t>(n) <= writable) {
    writer_index_ += n;
  } else {
    writer_index_ = buffer_.size();
    Append(extrabuf, n - writable);
  }
  return n;
}

}  // namespace net
}  // namespace xlcomm